package org.cdc.divination.frame.register;


import org.bukkit.Bukkit;
import org.bukkit.command.PluginCommand;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.event.Listener;
import org.cdc.divination.frame.annotation.EventListener;
import org.cdc.divination.frame.annotation.Data;
import org.cdc.divination.frame.annotation.RootCommand;
import org.cdc.divination.frame.data.DataPool;
import org.cdc.divination.frame.parents.AbstractCommandExecutor;
import org.cdc.divination.frame.parents.AbstractPlugin;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.List;

public class Register {
    private List<Class<?>> registeredClasses;
    private AbstractPlugin pluginInstance;
    public Register(AbstractPlugin plugin){
        this.pluginInstance=plugin;
    }
    public void registerClass(Class<?> registeredClass) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        if (registeredClass.isAnnotationPresent(RootCommand.class)) {
            registeredClasses.add(registeredClass);
            AbstractCommandExecutor obj = (AbstractCommandExecutor) initClass(registeredClass);
            DataPool.addPublicData(obj.getClass().getName(), obj, true);
            PluginCommand command =pluginInstance.getCommand(registeredClass.getAnnotation(RootCommand.class).value());
            command.setExecutor(obj);
            command.setTabCompleter(obj);
            obj.initExecutor();

        } else if (registeredClass.isAnnotationPresent(EventListener.class)){
            Listener listener = (Listener) initClass(registeredClass);
            Bukkit.getPluginManager().registerEvents(listener,pluginInstance);
            DataPool.addPublicData(listener.getClass().getName(),listener,true);
        }
        return;
    }
    public static Object initClass(Class<?> cla) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //实例化类
        final Object obj = cla.getConstructor().newInstance();
        //得到所有共有的成员变量(域)
        return initClass(obj);
    }
    public static Object initClass(Object made){
        Class<?> cla = made.getClass();
        Arrays.stream(cla.getFields()).forEach(a->{
            if (!a.isAnnotationPresent(Data.class)){
                return;
            }
            try {
                Data data = a.getAnnotation(Data.class);
                a.set(made,getData(data,a.getName(),a.getType().getName()));
            } catch (IllegalAccessException | ClassNotFoundException | InvocationTargetException | NoSuchMethodException | InstantiationException e) {
                e.printStackTrace();
            }
        });
        return made;
    }
    public static Object getData(Data data,String name,String typeName) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        if (data == null) return DataPool.getPublicDataByCondition(name,typeName);
        switch (data.from()){
            case DataPool:
                return DataPool.getPublicDataByCondition(("".equals(data.dataName()))?name:data.dataName(),typeName);
            case Config:
                if (data.dataName().contains(":")){
                    String[] splits = data.dataName().split(":");
                    YamlConfiguration yml = YamlConfiguration.loadConfiguration(new File(splits[0]));
                    return yml.get(splits[1]);
                } else return ((AbstractPlugin)DataPool.getPublicData("pluginInstance")).getConfig().get(data.dataName());
            case DataPack:
                return initClass(Class.forName(typeName));
            default:
                return null;
        }
    }
    public static Object[] getParams(Parameter[] parameters) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        Object[] args = new Object[parameters.length];
        for (int index=0;index< args.length;index++){
            Parameter parameter = parameters[index];
            args[index]=getData((parameter.isAnnotationPresent(Data.class))?parameter.getAnnotation(Data.class):null,parameter.getName(),parameter.getType().getName());
        }
        return args;
    }
}
